﻿namespace ScrumLite.Data
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using ScrumLite.Data;
    using System.Collections.ObjectModel;

    public class ProjectStore: IProjectStore
    {        
        public void Add(Project project)
        {
            using (ScrumLiteDataContext context = new ScrumLiteDataContext())
            {
                context.Log = new DebuggerWriter();
                var proj = new Project()
                {
                    id = project.id,
                    name = project.name,
                    endsOn = project.endsOn,
                    startsOn = project.startsOn,
                    security_group = project.security_group,
                    uri_repository = project.uri_repository,
                    user_ownedBy = project.user_ownedBy,
                    uri_projectSpecificMetrics = project.uri_projectSpecificMetrics
                };

                context.Projects.InsertOnSubmit(proj);
                context.SubmitChanges();
            }
        }

        public Project[] GetProjects()
        {
            using (ScrumLiteDataContext context = new ScrumLiteDataContext())
            {
                var projects = context.Projects.OrderBy( proj => proj.name);
                
                return projects.ToArray();
            }
        }

        public Project GetProject(Guid projectId)
        {
            using (ScrumLiteDataContext context = new ScrumLiteDataContext())
            {
                Project project  = context.Projects.SingleOrDefault(r => r.id == projectId);
                return project;
            }
        }

        public Project GetProjectByName(string projectName)
        {
            using (ScrumLiteDataContext context = new ScrumLiteDataContext())
            {
                Project project = context.Projects.SingleOrDefault(r => r.name == projectName);
                return project;
            }
        }

        public Dictionary<ProjectPerson, List<Role>> GetPeople(Guid projectId)
        {
            Dictionary<ProjectPerson, List<Role>> people = new Dictionary<ProjectPerson, List<Role>>();
            using (ScrumLiteDataContext context = new ScrumLiteDataContext())
            {
                var projectPerson = (from p in context.ProjectPersons
                                 where p.fk_project == projectId
                                 select p).ToArray();
                foreach (ProjectPerson pp in projectPerson)
                {
                    List<Role> roles = (from r in context.Roles
                                        from p in context.ProjectPersonRoles
                                        where p.Role.id == r.id &&
                                        pp.ProjectPersonRoles.Contains(p)
                                        select r).ToList<Role>();

                    people.Add(pp, roles);
                }
            }
            return people;
        }

        public void AddPerson(ProjectPerson person)
        {
            using (ScrumLiteDataContext context = new ScrumLiteDataContext())
            {
                context.Log = new DebuggerWriter();
                var projectperson = new ProjectPerson()
                {
                    id = person.id,
                    fk_project = person.fk_project,
                    isInternal = person.isInternal,
                    samAccountName = person.samAccountName
                };

                context.ProjectPersons.InsertOnSubmit(projectperson);
                context.SubmitChanges();
            }
        }

        public void AddPersonRole(ProjectPersonRole personRole)
        {
            using (ScrumLiteDataContext context = new ScrumLiteDataContext())
            {
                context.Log = new DebuggerWriter();
                var projectpersonrole = new ProjectPersonRole()
                {
                    fk_projectPerson = personRole.fk_projectPerson,
                    fk_role = personRole.fk_role
                };

                context.ProjectPersonRoles.InsertOnSubmit(projectpersonrole);
                context.SubmitChanges();
            }
        }

        public void RemovePerson(Guid projectId, string personId)
        {
            using (ScrumLiteDataContext context = new ScrumLiteDataContext())
            {
                context.Log = new DebuggerWriter();

                foreach (ProjectPerson projectperson in (from p in context.ProjectPersons where p.samAccountName.Equals(personId) select p)) {
                    foreach (ProjectPersonRole role in (from r in context.ProjectPersonRoles where r.fk_projectPerson.Equals(projectperson.id) select r))
                        context.ProjectPersonRoles.DeleteOnSubmit(role);
                    context.ProjectPersons.DeleteOnSubmit(projectperson);
                }

                context.SubmitChanges();
            }
        }

        public Dictionary<string, string[]> CheckProjectCompliance(Guid projectId)
        {
            Dictionary<string, string[]> checkList = new Dictionary<string, string[]>();
            using (ScrumLiteDataContext context = new ScrumLiteDataContext())
            {
                #region Generales del proyecto
                
                //Project sin WorkAreas
                var workAreas = (from wa in context.WorkAreas
                                 where wa.fk_project == projectId
                                 select wa.id);
                checkList.Add("Has Work Areas created", (workAreas.Count() == 0 ? new string[] { "The project hasn't Work Areas created" } : null));

                //Project sin Personas
                var persons = (from p in context.ProjectPersons
                               where p.fk_project == projectId
                               select p.id);
                checkList.Add("Has People assigned", (persons.Count() == 0 ? new string[] { "The project hasn't People assigned" } : null));
                
                //Project sin Roles
                var roles = (from r in context.ProjectRoles
                             where r.fk_project == projectId
                             select r.id);
                checkList.Add("Has Roles assigned", (roles.Count() == 0 ? new string[] { "The project hasn't Roles assigned" } : null));

                #endregion

                //Defect asociado a request
                var defectToRequest = (from d in context.Defects
                                       where d.decision.Contains("href")==false &&
                                       d.Deliverable.pk_project == projectId
                                       select "The Defect "+ d.moniker.ToString() + " hasn't a request associated");
                checkList.Add("All Defects are linked to a Requests", defectToRequest.ToArray());

                //Deliverable con WorkArea
                var deliverableToWorkArea = (from d in context.Deliverables
                                             where d.pk_project == projectId &&
                                             d.DeliverableWorkAreas.Count() == 0
                                             select "The Deliverable " + d.fileName + " hasn't a work area associated");
                checkList.Add("All Deliverables are related to a Work Area",deliverableToWorkArea.ToArray());

                //Requests con WorkArea
                var requestToWorkArea = (from r in context.Requests
                                         where r.fk_project == projectId &&
                                         r.RequestWorkAreas.Count() == 0
                                         select "The Request " + r.moniker + " hasn't a work area associated");
                checkList.Add("All Requests are related to a Work Area", requestToWorkArea.ToArray());
            }
            return checkList;
        }

        public void Update(Project project)
        {
            using (ScrumLiteDataContext context = new ScrumLiteDataContext())
            {
                context.Log = new DebuggerWriter();
                var proj = context.Projects.SingleOrDefault(p => p.id == project.id);
                if (proj != null)
                {
                    proj.name = project.name;
                    proj.endsOn = project.endsOn;
                    proj.startsOn = project.startsOn;
                    proj.security_group = project.security_group;
                    proj.uri_repository = project.uri_repository;
                    proj.uri_projectSpecificMetrics = project.uri_projectSpecificMetrics;
                 context.SubmitChanges();
                }
            }
        }

        public Dictionary<string,Collection<ComplianceChecker>> GetComplianceCheckerProperties()
        {
            using (ScrumLiteDataContext context = new ScrumLiteDataContext())
            {
                Dictionary<string, Collection<ComplianceChecker>> properties = new Dictionary<string, Collection<ComplianceChecker>>();
                foreach(ComplianceChecker property in context.ComplianceCheckers)
                {
                    if (properties.Keys.Contains(property.property))
                    {
                        properties[property.property].Add(property);
                    }
                    else
                    {
                        properties.Add(property.property, new Collection<ComplianceChecker>() { property });
                    }
                }

                return properties;
            }
        }
    }
}
